﻿namespace SpecificationPattern;

//规格模式 类似Linq
public class Food
{
    public string Name { get; set; }
    public bool IsGlutenFree { get; set; }
    public bool IsLowCalorie { get; set; }
    public bool IsVegetarian { get; set; }
}

public interface ISpecification<T>
{
    bool IsSatisfiedBy(T item);
}

public interface ICompositeSpecification<T> : ISpecification<T>
{
    ICompositeSpecification<T> And(ISpecification<T> other);
    ICompositeSpecification<T> Or(ISpecification<T> other);
}

public class CompositeSpecification<T> : ICompositeSpecification<T>
{
    private readonly List<ISpecification<T>> _specifications = new List<ISpecification<T>>();

    public CompositeSpecification(params ISpecification<T>[] specifications)
    {
        _specifications.AddRange(specifications);
    }

    public bool IsSatisfiedBy(T item)
    {
        return _specifications.All(spec => spec.IsSatisfiedBy(item));
    }

    public ICompositeSpecification<T> And(ISpecification<T> other)
    {
        _specifications.Add(other);
        return this;
    }

    public ICompositeSpecification<T> Or(ISpecification<T> other)
    {
        return new CompositeSpecification<T>(_specifications.Concat(new[] { other }).ToArray());
    }
}

public class GlutenFreeSpecification : ICompositeSpecification<Food>
{
    public bool IsSatisfiedBy(Food item)
    {
        return item.IsGlutenFree;
    }

    public ICompositeSpecification<Food> And(ISpecification<Food> other)
    {
        return new CompositeSpecification<Food>(this, other);
    }

    public ICompositeSpecification<Food> Or(ISpecification<Food> other)
    {
        return new CompositeSpecification<Food>(this, other);
    }
}

public class LowCalorieSpecification : ICompositeSpecification<Food>
{
    public bool IsSatisfiedBy(Food item)
    {
        return item.IsLowCalorie;
    }

    public ICompositeSpecification<Food> And(ISpecification<Food> other)
    {
        return new CompositeSpecification<Food>(this, other);
    }

    public ICompositeSpecification<Food> Or(ISpecification<Food> other)
    {
        return new CompositeSpecification<Food>(this, other);
    }
}

public class VegetarianSpecification : ICompositeSpecification<Food>
{
    public bool IsSatisfiedBy(Food item)
    {
        return item.IsVegetarian;
    }

    public ICompositeSpecification<Food> And(ISpecification<Food> other)
    {
        return new CompositeSpecification<Food>(this, other);
    }

    public ICompositeSpecification<Food> Or(ISpecification<Food> other)
    {
        return new CompositeSpecification<Food>(this, other);
    }
}

public static class Program
{
    public static void Main()
    {
        var foods = new List<Food>
        {
            new() { Name = "汉堡", IsGlutenFree = false, IsLowCalorie = false, IsVegetarian = false },
            new() { Name = "沙拉", IsGlutenFree = true, IsLowCalorie = true, IsVegetarian = true },
            new() { Name = "披萨", IsGlutenFree = true, IsLowCalorie = false, IsVegetarian = true }
        };

        // 创建一个复合规格，找出既不含麸质又低热量的食物
        var spec = new GlutenFreeSpecification().And(new LowCalorieSpecification());
        var suitableFoods = foods.Where(food => spec.IsSatisfiedBy(food)).ToList();

        // 输出符合条件的食物名称
        suitableFoods.ForEach(food => Console.WriteLine(food.Name));
    }
}